/*
 * pi3's Linux kernel Runtime Guard
 *
 * Component:
 *  - Generic install and uninstall functions
 *
 * Notes:
 *  - None
 *
 * Caveats:
 *  - None
 *
 * Timeline:
 *  - Created: 4.V.2020
 *
 * Author:
 *  - Mariusz Zaborski (https://oshogbo.vexillium.org/)
 *
 */

#include "../../../p_lkrg_main.h"

int p_install_hook(struct kretprobe *kretprobe, char *state, int p_isra) {

   int p_ret;
   const char *p_name = kretprobe->kp.symbol_name;
   struct p_isra_argument p_isra_arg;

   if ( (p_ret = register_kretprobe(kretprobe)) < 0) {
      if (p_isra && p_ret == -22) {
         p_print_log(P_LKRG_WARN, "[kretprobe] register_kretprobe() for <%s> failed! [err=%d]\n",
                     p_name, p_ret);
         p_print_log(P_LKRG_WARN, "Trying to find ISRA / CONSTPROP name for <%s>\n",p_name);
         p_isra_arg.p_name = p_name;
         p_isra_arg.p_isra_name = NULL;
         if (p_try_isra_name(&p_isra_arg)) {
            p_name = kretprobe->kp.symbol_name = p_isra_arg.p_isra_name;
            if ( (p_ret = register_kretprobe(kretprobe)) < 0) {
               p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() for <%s> failed! [err=%d]\n",
                      p_name, p_ret);
               return p_ret;
            }
            p_print_log(P_LKRG_WARN,
                        "ISRA / CONSTPROP version was found and hook was planted at <%s>\n",
                        p_name);
            (*state)++;
         } else {
            p_print_log(P_LKRG_ERR,
                   "[kretprobe] register_kretprobe() for %s failed and ISRA / CONSTPROP version not found!\n",
                   p_isra_arg.p_name);
            return p_ret;
         }
      } else {
         p_print_log(P_LKRG_ERR, "[kretprobe] register_kretprobe() for <%s> failed! [err=%d]\n",
                     p_name, p_ret);
         return p_ret;
      }
   }

   p_print_log(P_LKRG_INFO, "Planted [kretprobe] <%s> at: 0x%lx\n",
               p_name,
               (unsigned long)kretprobe->kp.addr);
   (*state)++;

   return p_ret;
}

void p_uninstall_hook(struct kretprobe *kretprobe, char *state) {

   const char *p_name = kretprobe->kp.symbol_name;

   if (!*state) {
      p_print_log(P_LKRG_INFO, "[kretprobe] <%s> at 0x%lx is NOT installed\n",
                  p_name,
                  (unsigned long)kretprobe->kp.addr);
   } else {
      unregister_kretprobe(kretprobe);
      p_print_log(P_LKRG_INFO, "Removing [kretprobe] <%s> at 0x%lx nmissed[%d]\n",
                  p_name,
                  (unsigned long)kretprobe->kp.addr,
                  kretprobe->nmissed);
      if (*state == 2) {
         // Free ISRA name buffer
         p_print_log(P_LKRG_INFO, "Freeing ISRA / CONSTPROP buffer[0x%lx]\n",
                     (unsigned long)kretprobe->kp.symbol_name);
         kfree(kretprobe->kp.symbol_name);
      }
      *state = 0;
   }
}
